﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Config_App
{
    /// <summary>
    /// Benutzersteuerelement für die vorhersage von zeitabläufen
    /// </summary>
    public partial class _uc_TIMESERIES : UserControl
    {
        public float[][] input;
        public float[][] output;

        public double[] data = null;
        private double[,] dataToShow = null;

        private double[,] windowDelimiter = new double[2, 2] { { 0, 0 }, { 0, 0 } };
        private double[,] predictionDelimiter = new double[2, 2] { { 0, 0 }, { 0, 0 } };

        public int windowSize = 5;
        public int predictionSize = 1;

        public _uc_TIMESERIES()
        {
            InitializeComponent();

            this._c_chart.AddDataSeries("data", Color.Red, AForge.Controls.Chart.SeriesType.Dots, 5);
            this._c_chart.AddDataSeries("solution", Color.Blue, AForge.Controls.Chart.SeriesType.ConnectedDots, 5);
            this._c_chart.AddDataSeries("window", Color.LightGray, AForge.Controls.Chart.SeriesType.Line, 1, false);
            this._c_chart.AddDataSeries("prediction", Color.Gray, AForge.Controls.Chart.SeriesType.Line, 1, false);
        }

        /// <summary>
        /// Update deleimiters auf dem Chart
        /// </summary>
        private void UpdateDelimiters()
        {
            // Fenster delimiter
            windowDelimiter[0, 0] = windowDelimiter[1, 0] = (double)this._nud_WS.Value;
            windowDelimiter[0, 1] = this._c_chart.RangeY.Min;
            windowDelimiter[1, 1] = this._c_chart.RangeY.Max;
            this._c_chart.UpdateDataSeries("window", windowDelimiter);
            // Vorhersage delimiter
            predictionDelimiter[0, 0] = predictionDelimiter[1, 0] = data.Length - 1 - (double)this._nud_PS.Value;
            predictionDelimiter[0, 1] = this._c_chart.RangeY.Min;
            predictionDelimiter[1, 1] = this._c_chart.RangeY.Max;
            this._c_chart.UpdateDataSeries("prediction", predictionDelimiter);
        }

        /// <summary>
        /// Aktualisert alle daten auf der gui (für realod)
        /// </summary>
        public void UPDATE_ALL_DATA()
        {
            this.UpdateDataListView();
            this.UpdateDelimiters();

            dataToShow = new double[this.data.GetLength(0), 2];
            for (int j = 0; j < this.data.GetLength(0); j++)
            {
                dataToShow[j, 0] = j;
                dataToShow[j, 1] = data[j];
            }

            this._c_chart.RangeX = new AForge.Range(0, data.Length - 1);
            this._c_chart.UpdateDataSeries("data", dataToShow);
        }

        /// <summary>
        /// aktualisert die daten in der LV
        /// </summary>
        private void UpdateDataListView()
        {
            this._lv_main.Items.Clear();
            

            for (int i = 0, n = data.GetLength(0); i < n; i++)
            {
                this._lv_main.Items.Add(data[i].ToString());
            }
        }

        /// <summary>
        /// Lädt Daten von der Festplatte. Stellt alle dialoge bereit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_load_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Datendateien|*.csv";
            ofd.InitialDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(_uc_APPROX)).Location) + "\\BEISPIELE\\TIMESERIES\\";

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                System.IO.StreamReader reader = null;
                // maximal 50 punkte
                double[] tempData = new double[50];

                try
                {
                    reader = System.IO.File.OpenText(ofd.FileName);
                    string str = null;
                    int i = 0;

                    while ((i < 50) && ((str = reader.ReadLine()) != null))
                    {
                        // werte parsen
                        tempData[i] = double.Parse(str);

                        i++;
                    }

                    data = new double[i];
                    dataToShow = new double[i, 2];
                    Array.Copy(tempData, 0, data, 0, i);
                    for (int j = 0; j < i; j++)
                    {
                        dataToShow[j, 0] = j;
                        dataToShow[j, 1] = data[j];
                    }
                }
                catch (Exception)
                {
                    MessageBox.Show("Fehler beim parsen der Datei!", "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
                finally
                {
                    if (reader != null)
                        reader.Close();
                }

                // LV und chart aktualiseren
                UpdateDataListView();
                this._c_chart.RangeX = new AForge.Range(0, data.Length - 1);
                this._c_chart.UpdateDataSeries("data", dataToShow);
                this._c_chart.UpdateDataSeries("solution", null);
                
                UpdateDelimiters();
            }
        }

        /// <summary>
        /// erzeugt die konfiguration und stellt diese bereit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _b_ok_Click(object sender, EventArgs e)
            {
            int samples = (int)(data.Length - this._nud_PS.Value - this._nud_WS.Value);
            double factor = 1.7 / this._c_chart.RangeY.Length;
            double yMin = this._c_chart.RangeY.Min;
            
            // erzeuge arrays
            input = new float[samples][];
            output = new float[samples][];

            for (int i = 0; i < samples; i++)
            {
                input[i] = new float[(int)this._nud_WS.Value];
                output[i] = new float[1];

                // eingabe setzten
                for (int j = 0; j < (int)this._nud_WS.Value; j++)
                {
                    input[i][j] = (float)((data[i + j] - yMin) * factor - 0.85);
                }
                // ausgabe setzten
                output[i][0] = (float)((data[i + (int)this._nud_WS.Value] - yMin) * factor - 0.85);
            }

            this.windowSize = (int)this._nud_WS.Value;
            this.predictionSize = (int)this._nud_PS.Value;

            UpdateDelimiters();
        }
    }
}
